#include "action.h"
#include <QFont>
#include <QPainter>
#include <QDebug>
#include <QLineF>
#include <QTextLayout>
#include <QGraphicsDropShadowEffect>
#include "pdlg_action.h"

ActionShape *ActionShape::clone() const
{
	ActionShape *newshape = new ActionShape();
	newshape->setPos(this->pos());
	newshape->setSize(this->size());
	newshape->setTitle(this->title());
	newshape->setDescription(this->description());
	return newshape;
}

ActionShape::ActionShape (const QPointF &pos, QGraphicsItem *parent)
	: ResizableShape(pos, parent)
{
	setMinSize(QSizeF(50,32));
	setTitle(tr("Action"));
	setSize(QSizeF(100,32));
}

ActionShape::ActionShape (QGraphicsItem *parent)
	: ResizableShape(parent)
{
	setMinSize(QSizeF(50, 32));
	setTitle(tr("Action"));
	//adjustSize();
	setSize(QSizeF(100,32));
}

/**
 * Задает текст на фигуре.
 * @param newtext Новое значение
 */
void ActionShape::setTitle (const QString &newtext)
{
	prepareGeometryChange();
	_title = newtext;
	emit contentsChanged();
}

/**
 * @return Текст на фигуре.
 */
const QString &ActionShape::title() const
{
	return _title;
}

/**
 * Задает описание фигуры (фактически, подсказку).
 * @param newtext Новый текст подсказки
 */
void ActionShape::setDescription (const QString &newtext)
{
	setToolTip(newtext);
	_description = newtext;
	emit contentsChanged();
}

/**
 * @return Текст подсказки
 */
const QString &ActionShape::description() const
{
	return _description;
}

/**
 * Возвращает минимальный прямоугольник, в который помещается текст.
 * @param text Текст
 * @param font Шрифт, которым рисуется текст
 * @param width Ширина фигуры (она останется неизменной)
 * @param option Параметры отображения
 * @return Размер прямоугольника.
 */
QSizeF textRect (const QString &text, const QFont &font, int width, const QTextOption &option)
{
	QTextLayout textLayout(text, font);
	QFontMetricsF metrics(font);
	int leading = metrics.leading();
	qreal height = 0;
	textLayout.setTextOption(option);
	textLayout.beginLayout();
	int length = 0;
	while(true)
	{
		QTextLine line = textLayout.createLine();
		if (!line.isValid()) break;
		line.setLineWidth(width);
		height += leading + line.height();
		length += line.textLength();
	}
	textLayout.endLayout();
	return QSizeF(width, height);//textLayout.boundingRect().size();
}

/**
 * Возвращает сокращенный текст, такой, чтобы не превышал указанных размеров при рендеринге.
 * @param text Текст, который нужно сократить.
 * @param font Шрифт, которым выводится текст.
 * @param sz Максимальные размеры текста.
 * @param option Всякие опции для текста. Будут использованы в QTextLayout.
 * @returns Сокращенный текст (с многоточием на конце).
 *          Если весь помещается - то весь и будет возвращен.
 */
QString elidedText (const QString &text, const QFont &font, const QSizeF &sz, const QTextOption &option)
{
	// Все-таки Qt - это тот еще быдлокод
	// Вязкое де*ьмо объектных конструкций
	// Надо потом ее, эту функцию, в утилиты перенести

	/*
	 Сначала определим длину текста, который умещается в прямоугольнике
	 Для этого найдем количество строк, которые там умещаются (+ еще переводы!)
	 И затем суммируем их длины
	*/
	QTextLayout textLayout(text, font);
	QFontMetricsF metrics(font);
	int leading = metrics.leading();
	qreal height = 0;
	textLayout.setTextOption(option);
	textLayout.beginLayout();
	int length = 0;
	while(true)
	{
		QTextLine line = textLayout.createLine();
		if (!line.isValid()) break;
		line.setLineWidth(sz.width());
		height += leading + line.height();
		if (height>sz.height()) break;
		length += line.textLength();
	}
	textLayout.endLayout();
	QString str = text.left(length); // Это наша искомая строка, но без многоточия

	/*
	 Теперь нужно найти, сколько текста поместится вместе с многоточием.
	 Следует учитывать, что, если текст можно отобразить полностью,
	 многоточия не требуется.
	*/
	QRectF shaperect = QRectF(0,0,sz.width(),sz.height());
	QRectF shaperecth = QRectF(0,0,sz.width(),sz.height()*2); // очень высокий, чтобы можно было узнать реальную высоту текста.
	while(true)
	{
		// мало ли, вдруг зацикливание
		if (str.length()==0) break;

		// Выполняем цикл, пока текст не помещается в прямоугольник rect
		QRectF rect = metrics.boundingRect(
				shaperecth,
				Qt::AlignLeft | Qt::TextWordWrap,
				str + (str.length()==text.length()? "" : "..."));
		if (shaperect.contains(rect))
			break;

		// Отрезаем один символ и снова будем пытаться уместить его
		str = str.left(str.length()-1);
	}

	// собственно вот! ради чего все затевалось
	return str + (str.length()==text.length()? "" : "..."); // и так сойдет
}

/**
 * Подогнать размер фигуры
 * (если он меньше минимального, то увеличить).
 */
void ActionShape::adjustSize()
{
	QTextOption textoption;
	textoption.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
	textoption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
	QSizeF minsz = textRect(
			title(),
			Shape::basicFont(),
			size().width()-14,
			textoption
	);
	setMinSize(QSizeF(minSize().width(), minsz.height()+14));
	if (size().height() < minSize().height())
		setSize(QSizeF(size().width(), minSize().height()));
}

void ActionShape::paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
	adjustSize();
	painter->setFont(Shape::basicFont());
	painter->setPen(Qt::SolidLine);
	painter->setBrush(Shape::innerBrush());
	painter->drawPath(shape());
	QTextOption textoption;
	textoption.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
	textoption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
	painter->drawText(
			QRectF(7,7,size().width()-14, size().height()-14),
			title(),
			textoption
	);

	/*painter->drawText(
			QRectF(QPointF(0,0), QPointF(size().width(), size().height()))
				.adjusted(7,7,-7,-7),
			elidedText(_title, painter->font(), size()-QSizeF(14,14), textoption),
			textoption);*/
	if (isSelected())
	{
		QRectF rect = boundingRect();
		rect.adjust(3,3,-3,-3);
		setPenAndBrushForSelection(painter);
		painter->drawRoundedRect(rect, 5,5);
	}
}

QPainterPath ActionShape::shape() const
{
	QPainterPath path;
	path.addRoundedRect(boundingRect(), 10,10);
	return path;
}

void ActionShape::editProperties()
{
	ActionShapePropertiesDialog(this).exec();
}
